import plotly.express as px
import pandas as pd


df = pd.read_excel('df_with_per_capita_gdp.xlsx')


# 查看数据结构
print("数据基本信息:")
print(df.info())
print("\n数据前5行:")
print(df.head())
print("\n列名:")
print(df.columns.tolist())

# 检查数据完整性
print(f"\n数据行数: {len(df)}")
print(f"国家数量: {df['country_name'].nunique()}")
print(f"年份范围: {df['time_period'].min()} - {df['time_period'].max()}")
print(f"人均GDP范围: {df['obs_value'].min():.2f} - {df['obs_value'].max():.2f}")
print(f"住宅投资占比范围: {df['ratio'].min():.2f}% - {df['ratio'].max():.2f}%")

# 删除缺失值
df_clean = df.dropna()
print(f"\n清理后数据行数: {len(df_clean)}")


# 使用plotly绘制散点图
fig = px.scatter(
    df_clean,
    x='obs_value',  # 人均GDP为横轴
    y='ratio',      # 住宅投资占GDP比例为纵轴
    color='country_name',  # 用颜色区分国家
    symbol='time_period',  # 用标记区分年份
    title='住宅投资占比与人均GDP发展阶段关系',
    labels={
        'obs_value': '人均GDP',
        'ratio': '住宅投资占GDP比例（%）',
        'country_name': '国家',
        'time_period': '年份'
    },
    hover_data=['country_name', 'time_period', 'ratio', 'obs_value'],
    size_max=15
)

# 更新图表布局
fig.update_layout(
    xaxis_title='人均GDP',
    yaxis_title='住宅投资占GDP比例（%）',
    legend_title='国家/年份',
    showlegend=True,
    legend=dict(
        orientation="v",
        yanchor="top",
        y=1,
        xanchor="left",
        x=1.02
    )
)

# 显示图表
# fig.show()

# 保存图表为HTML文件
fig.write_html('住宅投资与人均GDP散点图.html')

# 高级设置：自定义标记和颜色
fig_advanced = px.scatter(
    df_clean,
    x='obs_value',
    y='ratio',
    color='country_name',
    symbol='time_period',
    title='住宅投资占比与人均GDP发展阶段关系（高级设置）',
    labels={
        'obs_value': '人均GDP',
        'ratio': '住宅投资占GDP比例（%）',
        'country_name': '国家',
        'time_period': '年份'
    },
    hover_data=['country_name', 'time_period', 'ratio', 'obs_value'],
    size_max=15,
    opacity=0.7,  # 设置透明度
    template='plotly_white'  # 使用白色主题
)

# 自定义标记大小和样式
fig_advanced.update_traces(
    marker=dict(size=10, line=dict(width=1, color='DarkSlateGrey'))
)

# 更新布局
fig_advanced.update_layout(
    xaxis_title='人均GDP',
    yaxis_title='住宅投资占GDP比例（%）',
    legend_title='国家/年份',
    showlegend=True,
    xaxis=dict(
        showgrid=True,
        gridwidth=1,
        gridcolor='LightGray'
    ),
    yaxis=dict(
        showgrid=True,
        gridwidth=1,
        gridcolor='LightGray'
    )
)

# fig_advanced.show()
fig_advanced.write_html('adv_住宅投资与人均GDP散点图.html')
print("高级散点图已保存为 'adv_住宅投资与人均GDP散点图.html'")


# 动画散点图：按年份显示变化
fig_animated = px.scatter(
    df_clean,
    x='obs_value',
    y='ratio',
    color='country_name',
    animation_frame='time_period',  # 按年份动画
    title='住宅投资占比与人均GDP发展阶段关系（按年份动画）',
    labels={
        'obs_value': '人均GDP',
        'ratio': '住宅投资占GDP比例（%）',
        'country_name': '国家',
        'time_period': '年份'
    },
    hover_data=['country_name', 'time_period', 'ratio', 'obs_value'],
    size_max=15
)

# 更新动画设置
fig_animated.update_layout(
    xaxis_title='人均GDP',
    yaxis_title='住宅投资占GDP比例（%）',
    legend_title='国家',
    showlegend=True
)

# fig_animated.show()
fig_animated.write_html('动画住宅投资与人均GDP散点图.html')
print("动画散点图已保存为 '动画住宅投资与人均GDP散点图.html'")


# 方法3：使用自定义图例设置
import plotly.graph_objects as go

# 获取所有国家
countries = df_clean['country_name'].unique()

# 创建图表
fig_custom = go.Figure()

# 为每个国家添加数据
for country in countries:
    country_data = df_clean[df_clean['country_name'] == country]
    
    fig_custom.add_trace(go.Scatter(
        x=country_data['obs_value'],
        y=country_data['ratio'],
        mode='markers',
        name=country,  # 只显示国家名称
        marker=dict(size=8),
        text=country_data['time_period'].astype(str),  # 在hover中显示年份
        hovertemplate='<b>%{customdata[0]}</b><br>年份: %{text}<br>人均GDP: %{x:.2f}<br>住宅投资占比: %{y:.2f}%<extra></extra>',
        customdata=country_data[['country_name']].values
    ))

# 更新布局
fig_custom.update_layout(
    title='住宅投资占比与人均GDP发展阶段关系（自定义图例）',
    xaxis_title='人均GDP',
    yaxis_title='住宅投资占GDP比例（%）',
    legend_title='国家',
    showlegend=True
)

# fig_custom.show()
fig_custom.write_html('住宅投资与人均GDP散点图_自定义图例.html')
print("自定义图例散点图已保存为 '住宅投资与人均GDP散点图_自定义图例.html'")